import {
  VuexModule,
  Module,
  Action,
  Mutation,
  getModule,
} from 'vuex-module-decorators'
import { login, logout, getUserInfo } from '@/api/users'
import { getToken, setToken, removeToken } from '@/utils/cookies'
import router, { resetRouter, asyncRoutes } from '@/router'
import { PermissionModule } from './permission'
import { TagsViewModule } from './tags-view'
import store from '@/store'
import { RouteConfig } from 'vue-router'
import Layout from '@/layout/index.vue'
import componentDic from '@/router/componentDic'
import { EmailModule } from './email'
import { SendEmailSettingsModule } from './sendEmailSettings'
const _import = require('@/router/_import_' + process.env.NODE_ENV)
export interface IUserState {
  token: string
  username: string
  userType: string
  name: string
  avatar: string
  introduction: string
  roles: string[]
  email: string
  routes: RouteConfig[]
}

@Module({ dynamic: true, store, name: 'user' })
class User extends VuexModule implements IUserState {
  public token = getToken() || ''
  public userId = ''
  public username = ''
  public settings: {
    validateEmailBeforeExport: boolean
    onlyExportValidEmails: boolean
  } = { validateEmailBeforeExport: false, onlyExportValidEmails: false }
  public userType = ''
  public name = ''
  public avatar = ''
  public introduction = ''
  public roles: string[] = []
  public email = ''
  public routes: RouteConfig[] = []

  @Mutation
  private SET_TOKEN(token: string) {
    this.token = token
  }

  @Mutation
  private SET_NAME(name: string) {
    this.name = name
  }

  @Mutation
  private SET_SETTINGS(settings: any) {
    this.settings = settings
  }

  @Mutation
  private SET_USERNAME(username: string) {
    this.username = username
  }

  @Mutation
  public SET_AVATAR(avatar: string) {
    this.avatar = avatar
  }

  @Mutation
  private SET_INTRODUCTION(introduction: string) {
    this.introduction = introduction
  }

  @Mutation
  private SET_ROLES(roles: string[]) {
    this.roles = roles
  }

  @Mutation
  private SET_EMAIL(email: string) {
    this.email = email
  }

  @Mutation
  private SET_ROUTES(routes: RouteConfig[]) {
    this.routes = routes
  }

  @Mutation
  private SET_USER_TYPE(userType: string) {
    this.userType = userType
  }

  @Mutation
  private SET_USER_ID(userId: string) {
    this.userId = userId
  }

  @Action
  public async Login(userInfo: { username: string; password: string }) {
    let { username, password } = userInfo
    username = username.trim()
    const { data } = await login({ userName: username, passWord: password })
    setToken(data.accessToken)
    this.SET_TOKEN(data.accessToken)
  }

  @Action
  public ResetToken() {
    removeToken()
    this.SET_TOKEN('')
    this.SET_ROLES([])
  }

  @Action
  public async GetUserInfo() {
    if (this.token === '') {
      throw Error('GetUserInfo: token is undefined!')
    }
    const { data } = await getUserInfo({
      /* Your params here */
    })
    if (!data) {
      throw Error('Verification failed, please Login again.')
    }
    const {
      roles,
      name,
      username,
      avatar,
      introduction,
      email,
      type,
      id,
      settings,
    } = data.user
    // roles must be a non-empty array
    if (!roles || roles.length <= 0) {
      throw Error('GetUserInfo: roles must be a non-null array!')
    }
    const f = (m: any) => {
      if (m.component && typeof m.component === 'string') {
        if (m.component === 'Layout') {
          m.component = Layout
        } else {
          // @ts-ignore
          m.component = componentDic[m.component]
        }
        m?.children?.map(f)
      }
      return m
    }
    this.SET_ROUTES(data.routes.map(f))
    // this.SET_ROUTES(asyncPrependRoutes)
    this.SET_ROLES(roles)
    this.SET_NAME(name)
    this.SET_USER_ID(id)
    this.SET_USERNAME(username)
    this.SET_AVATAR(avatar)
    this.SET_INTRODUCTION(introduction)
    this.SET_EMAIL(email)
    this.SET_USER_TYPE(type)
    this.SET_SETTINGS(settings)

    EmailModule.InitEmail(id)
    SendEmailSettingsModule.InitSendEmailSetting(id)
  }

  @Action({ rawError: true })
  public async ChangeRoles(role: string) {
    // Dynamically modify permissions
    const token = role + '-token'
    this.SET_TOKEN(token)
    setToken(token)
    await this.GetUserInfo()
    resetRouter()
    // Generate dynamic accessible routes based on roles
    PermissionModule.GenerateRoutes({ roles: this.roles, routes: this.routes })
    // Add generated routes
    PermissionModule.dynamicRoutes.forEach((route) => {
      router.addRoute(route)
    })
    // Reset visited views and cached views
    TagsViewModule.delAllViews()
  }

  @Action
  public async LogOut() {
    if (this.token === '') {
      throw Error('LogOut: token is undefined!')
    }
    await logout()
    removeToken()
    resetRouter()

    // Reset visited views and cached views
    TagsViewModule.delAllViews()
    this.SET_TOKEN('')
    this.SET_ROLES([])
  }

  @Action
  public setName(name: string) {
    this.SET_NAME(name)
  }

  @Action
  public setSettings(settings: any) {
    this.SET_SETTINGS(settings)
  }
}

export const UserModule = getModule(User)
